import struct
import datetime
import pandas as pd

from tools.utils_mootdx import MootdxClientInstance, make_qfq
from z_tdx.lc5_read_write import lc5_read


def _df_to_list(df: pd.DataFrame) -> list[list]:
    result = []
    for _, row in df.iterrows():
        datetime_obj = pd.to_datetime(row['datetime'])
        date_str = datetime_obj.strftime('%Y%m%d')
        time_str = datetime_obj.strftime('%H%M')
        transformed_row = [
            date_str,
            time_str,
            float(row['open']),
            float(row['high']),
            float(row['low']),
            float(row['close']),
            float(row['amount'] / 1000),
            int(row['vol'] / 100),
            65536  # 固定值
        ]
        result.append(transformed_row)
    # print(result)
    return result


def _list_to_df(kline_list: list) -> pd.DataFrame:
    """
    将K线数据列表转换为指定格式的DataFrame
    参数: kline_list: 二维列表，每个子列表包含['日期', '时间', '开盘价', '最高价', '最低价', '收盘价', '成交额', '成交量', 0]
    返回: pd.DataFrame: 转换后的DataFrame，包含指定的列
    """
    # 检查输入是否为空
    if not kline_list:
        return pd.DataFrame()

    # 转换列表为DataFrame，先指定原始列名
    df = pd.DataFrame(kline_list, columns=[
        'date', 'time', 'open', 'high', 'low', 'close',
        'amount', 'volume', 'factor'
    ])

    # 合并日期和时间，创建datetime列
    df['datetime'] = df['date'] + ' ' + df['time']
    df['datetime'] = pd.to_datetime(df['datetime'])

    # 提取年、月、日、时、分
    df['year'] = df['datetime'].dt.year
    df['month'] = df['datetime'].dt.month
    df['day'] = df['datetime'].dt.day
    df['hour'] = df['datetime'].dt.hour
    df['minute'] = df['datetime'].dt.minute

    # 调整列的顺序为目标格式
    result_df = df[[
        'year', 'month', 'day', 'hour', 'minute', 'datetime',
        'open', 'close', 'high', 'low', 'amount', 'volume', 'factor'
    ]]

    # 设置datetime为索引
    result_df = result_df.set_index('datetime')

    return result_df


def write_df_to_lc(df: pd.DataFrame, file_path: str, mode: str = 'ab+'):
    if df is None or len(df) == 0:
        return

    with open(file_path, mode) as f:
        try:
            i = 0
            while i < len(df):
                # year  month  day  hour  minute  open  close  high  low  amount  volume
                a = datetime.date(df.index[i].year, df.index[i].month, df.index[i].day)
                x = a.__format__('%Y%m%d')
                b = datetime.time(df.index[i].hour, df.index[i].minute)
                y = b.__format__('%H%M')
                dt = x + y
                ymr = round(int(x) / 10000 - 2016) * 1300 + int(x) % 10000
                t = int(dt) % 10000
                tt = t // 100 * 60 + t % 100

                f.write(struct.pack('h', int(ymr)))
                f.write(struct.pack('h', tt))
                f.write(struct.pack('f', float(df['open'][i] * 100)))
                f.write(struct.pack('f', float(df['high'][i] * 100)))
                f.write(struct.pack('f', float(df['low'][i] * 100)))
                f.write(struct.pack('f', float(df['close'][i] * 100)))
                f.write(struct.pack('f', float(df['amount'][i])))
                f.write(struct.pack('i', int(df['volume'][i] / 100)))
                up = 0
                down = 1
                f.write(struct.pack('h', up))
                f.write(struct.pack('h', down))
                i = i + 1
        except TypeError as e:
            print(e)


def read_lc_to_df(file_path: str) -> pd.DataFrame:
    kline_list = lc5_read(file_path)
    return _list_to_df(kline_list)


def bfq_to_qfq(df: pd.DataFrame, symbol: str) -> pd.DataFrame:
    client = MootdxClientInstance().client
    try:
        xdxr = client.xdxr(symbol=symbol)
        if xdxr is not None and len(xdxr) > 0:
            xdxr['date_str'] = xdxr['year'].astype(str) + \
                               '-' + xdxr['month'].astype(str).str.zfill(2) + \
                               '-' + xdxr['day'].astype(str).str.zfill(2)
            xdxr['datetime'] = pd.to_datetime(xdxr['date_str'] + ' 09:35:00')  # for 5 mins klines only
            xdxr = xdxr.set_index('datetime')

            df = make_qfq(df, xdxr)
            return df
        return df
    except Exception as e:
        print(f'计算前复权异常，{symbol}返回不复权数据，错误: ', e)
        return None


def test_write_df():
    from mootdx.quotes import Quotes
    from tools.utils_basic import pd_show_all
    pd_show_all()
    print('测试写入df')
    client = Quotes.factory(market='std', multithread=True, heartbeat=False)
    df = client.bars(symbol='000001', frequency='day', offset=1, adjust='qfq')
    print(df)

    test_path = './_cache/test.lc5'
    print(df.tail(1).values)
    write_df_to_lc(df, test_path)


def test_read_df():
    # symbol = '603050'
    # symbol = '603269'
    symbol = '688239'
    ex = 'sh'

    test_path = f'./_cache/lc5/sh/{ex}{symbol}.lc5'
    print(test_path)

    df = read_lc_to_df(test_path)
    # print(df)
    df = bfq_to_qfq(df, symbol)
    print(df)


if __name__ == '__main__':
    from tools.utils_basic import pd_show_all
    pd_show_all()

    from warnings import simplefilter
    simplefilter(action='ignore', category=FutureWarning)

    # test_write_df()
    test_read_df()
